package es.deusto.ingenieria.is.Hanoi.formulation;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Stack;
import es.deusto.ingenieria.is.search.algorithms.Node;
import es.deusto.ingenieria.is.search.algorithms.SearchMethod;
import es.deusto.ingenieria.is.search.formulation.Problem;
import es.deusto.ingenieria.is.search.formulation.State;


public class Problema_Hanoi extends Problem{

	private int nDiscos;
	private int nSoportes;
	private int soporteInicial;
	private int soporteFinal;
	
	public Problema_Hanoi(int nDiscos, int nSoportes, int soporteInicial,
			int soporteFinal) {
		super();
		this.nDiscos = nDiscos;
		this.nSoportes = nSoportes;
		this.soporteInicial = soporteInicial;
		this.soporteFinal = soporteFinal;
		this.createInitialState();
		this.createFinalState();
		this.createOperators();
	}
	
	
	public void createInitialState () {
		ArrayList<Soporte> a=new ArrayList<Soporte>(nSoportes);
		for(int i=0;i<nSoportes;i++){
			if(i+1==this.soporteInicial){
			Stack<Disco> s=new Stack<Disco>();
			for(int j=0;j<this.nDiscos;j++){
				Disco d=new Disco(nDiscos-j);
				s.push(d);
			}
			a.add(i,new Soporte(i+1, this.nDiscos, s));
			}else{
				a.add(i,new Soporte(i+1, 0, new Stack<Disco>()));
			}
		}
		this.addInitialState(new Estado_Hanoi(a, this.getSoporteInicial(),this.getSoporteFinal(),this.getnDiscos()));
		
	}
	
	public void createFinalState(){
		ArrayList<Soporte> a=new ArrayList<Soporte>(nSoportes);
		for(int i=0;i<nSoportes;i++){
			if(i+1==this.soporteFinal){
			Stack<Disco> s=new Stack<Disco>();
			for(int j=0;j<this.nDiscos;j++){
				Disco d=new Disco(nDiscos-j);
				s.push(d);
			}
			a.add(i,new Soporte(i+1, this.nDiscos, s));
			}else{
				a.add(i,new Soporte(i+1, 0, new Stack<Disco>()));
			}
		}
		this.addFinalState(new Estado_Hanoi(a, this.getSoporteInicial(),this.getSoporteFinal(),this.getnDiscos()));
		
	}
	
	public void createOperators() {
		Estado_Hanoi eInicial=(Estado_Hanoi)this.getInitialStates().get(0);
		for(int i=0;i<nSoportes;i++){
			for(int j=0;j<nSoportes;j++){
				if(j!=i){
					this.addOperator(new Mover_Disco(eInicial.getSoportes().get(i),eInicial.getSoportes().get(j)));
				}
			}
		}
	}	
	
	public boolean isFinalState (State state) {
		if (state != null && state != null && state instanceof Estado_Hanoi) {
			Estado_Hanoi estado = (Estado_Hanoi)state;
			Estado_Hanoi eFinal=(Estado_Hanoi)this.getFinalStates().get(0);
			int i=0;
			boolean isFinal=true;
			while((i<this.nSoportes)&&(isFinal)){
				if(estado.getSoportes().get(i).equals(eFinal.getSoportes().get(i))){
					i++;
				}else{
					isFinal=false;
				}
			}
			return isFinal;
		}
		else
			return false;
		
	}

	public void solve(SearchMethod searchMethod) {		
		SimpleDateFormat formatter = new SimpleDateFormat("hh:mm:ss.SSS");
		System.out.println("* Start '" + searchMethod.getClass().getSimpleName() + "' (" + formatter.format(GregorianCalendar.getInstance().getTime()) + ")");
		Node finalNode = searchMethod.search(this, this.getInitialStates().get(0));
		System.out.println("* End   '" + searchMethod.getClass().getSimpleName() + "' (" + formatter.format(GregorianCalendar.getInstance().getTime()) + ")");		
			
		if (finalNode != null) {
			System.out.println("\n- :-) Solution found!");
			List<String> operators = new ArrayList<String>();
			searchMethod.solutionPath(finalNode, operators);
			searchMethod.createSolutionLog(operators);
			System.out.println("\n" + finalNode.getState());
		} else {
			System.out.println("\n- :-( Unable to find the solution!");
		}
	}

	public int getnDiscos() {
		return nDiscos;
	}

	public void setnDiscos(int nDiscos) {
		this.nDiscos = nDiscos;
	}

	public int getnSoportes() {
		return nSoportes;
	}

	public void setnSoportes(int nSoportes) {
		this.nSoportes = nSoportes;
	}

	public int getSoporteInicial() {
		return soporteInicial;
	}

	public void setSoporteInicial(int soporteInicial) {
		this.soporteInicial = soporteInicial;
	}

	public int getSoporteFinal() {
		return soporteFinal;
	}

	public void setSoporteFinal(int soporteFinal) {
		this.soporteFinal = soporteFinal;
	}


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Problema_Hanoi p=new  Problema_Hanoi(3, 3, 1, 3);
		/*Estado_Hanoi s=(Estado_Hanoi)p.getInitialStates().get(0);
		s.aString(p);
		System.out.println(p.isFinalState(s));
		System.out.println();
		Estado_Hanoi sf=(Estado_Hanoi)p.getFinalStates().get(0);
		sf.aString(p);
		System.out.println(p.isFinalState(sf));
		*/
	}

}
